package com.boot.message.netty.client.sender;

import com.boot.message.netty.client.NettyClientProperties;
import com.boot.message.netty.client.handler.AbstractClientChannelInitializer;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;

/**
 * @author 霜寒 <1621856595@qq.com>
 * @description netty客户端的对外接口
 * @date 2020/3/13 22:35
 **/
@Slf4j
@SuppressWarnings("all")
public class NettyClientSender {

    private NettyClientProperties nettyClientProperties;

    private AbstractClientChannelInitializer<SocketChannel> clientChannelInitializer;

    public NettyClientSender(NettyClientProperties nettyClientProperties, AbstractClientChannelInitializer<SocketChannel> clientChannelInitializer) {
        this.nettyClientProperties = nettyClientProperties;
        this.clientChannelInitializer = clientChannelInitializer;
    }

    private InetSocketAddress inetSocketAddress;

    private NioEventLoopGroup clientGroup;

    private InetSocketAddress getSocketAddress() {
        if (inetSocketAddress == null) {
            if (nettyClientProperties.getPort() == 0) {
                throw new RuntimeException("未设置 Netty 服务端口，无法连接服务！");
            } else {
                inetSocketAddress = new InetSocketAddress(nettyClientProperties.getHost(), nettyClientProperties.getPort());
            }
        }
        return inetSocketAddress;
    }

    private NioEventLoopGroup getClientGroup() {
        if (clientGroup == null) {
            clientGroup = new NioEventLoopGroup();
        }
        return clientGroup;
    }

    private Bootstrap bootstrap() {
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(getClientGroup())
                .channel(NioSocketChannel.class)
                .handler(clientChannelInitializer);
        bootstrap.option(ChannelOption.SO_KEEPALIVE, nettyClientProperties.isKeepAlive())
                .option(ChannelOption.SO_SNDBUF, nettyClientProperties.getBuffer())
                .option(ChannelOption.SO_RCVBUF, nettyClientProperties.getBuffer());
        return bootstrap;
    }

    private ChannelFuture channelFuture;

    public NettyClientSender connect() throws Exception {
        if (nettyClientProperties.isEnable()) {
            log.info("开启 Netty 客户端...");
            channelFuture = bootstrap().connect(getSocketAddress()).sync();
        }
        return this;
    }

    public NettyClientSender write(String data) {
        if (nettyClientProperties.isEnable()) {
            channelFuture.channel().writeAndFlush(data);
        }
        return this;
    }

    public void disconnect() {
        disconnect("exit");
    }

    protected void disconnect(String exitMsg) {
        if (nettyClientProperties.isEnable()) {
            log.info("关闭 Netty 客户端...");
            channelFuture.channel().closeFuture();
            channelFuture.channel().writeAndFlush(exitMsg)
                    .addListener(ChannelFutureListener.CLOSE);
            getClientGroup().shutdownGracefully();
        }
    }

}
